/* 8911106 302933981 Ofri Keidar */

/******************************************************************************
* Student Name: Ofri Keidar
* Exercise Name: Ex6
* File Description: Class Inventory's implementation
******************************************************************************/


#include "Inventory.h"

/***************************************************************************************
* function name: void addItem(const short itemNumber, const string name) throw (ItemExistsError, bad_alloc)
* The Input: Number and name for a new item
* The output: None
* The Function operation: If an item with given number does not exist, creates a new
* 						  item with given number and name and adds it to inventory.
* 						  Else, throws item number as an exception
***************************************************************************************/
void Inventory::addItem(const short itemNumber, const string name) throw (ItemExistsError, bad_alloc) {

	// check if there already is an item with given number
	if (m_catalog.end() != m_catalog.find(itemNumber)) {
		// item does not exist, throw exception
		throw ItemExistsError(itemNumber);
	}


	MyAuto_ptr<Item> newItemPtr = new Item(itemNumber, name); // create a new item with given values
	m_catalog[itemNumber] = newItemPtr; // add pointer for new item to catalog
	m_stock[itemNumber] = INIT_AMOUNT; // create a new entry for the new item and initialize its amount as initialization value
	return;
}

/***************************************************************************************
* function name: void orderStock(const short itemNum, const unsigned short amount) throw (NoItemError, bad_alloc)
* The Input: Number of item to be ordered and amount if items
* The output: None
* The Function operation: If item number does not exist in catalog, throws item number
* 					      as an exception.
* 					      If exist in catalog, creates an order and adds it to order tracker.
* 					      New order's number will be current size of order tracker plus 1,
* 					      therefore order numbers will start from 1 and will increment
* 					      after each order is made
***************************************************************************************/
void Inventory::orderStock(const short itemNum, const unsigned short amount) throw (NoItemError, bad_alloc) {
	// check if item number exists in catalog
	if (m_catalog.end() == m_catalog.find(itemNum)) {
		// item does not exist, throw exception
		throw NoItemError(itemNum);
	}

	MyAuto_ptr<Order> newOrderPtr = new Order(m_orderTracker.size() + INIT_ORDER_NUM, itemNum, amount); // create a new order with given values
	m_orderTracker[m_orderTracker.size() + INIT_ORDER_NUM] = newOrderPtr; // add pointer for new order to order tracker
	return;
}

/***************************************************************************************
* function name: void recieveStock(const int orderNum, const unsigned short amount)
* The Input: Number of order and amount of items received
* The output: None
* The Function operation: Finds order in order tracker, according to order number.
* 						  Uses order's decrementAmount in order to decrement amount
* 						  left in order. If order's entire amount is received, order
* 						  is removed from order tracker
***************************************************************************************/
void Inventory::recieveStock(const int orderNum, const unsigned short amount) {

	// update ordered item's amount in stock
	m_stock[ (*m_orderTracker[orderNum]).getItemNumer() ] += amount;
	// get order with given number in order tracker and update amount
	(*m_orderTracker[orderNum]).updateAmount(amount);
}

/***************************************************************************************
* function name: void sellItem(const short itemNum, const int amount) throw (NoItemError, TooManyOrderedError, bad_alloc)
* The Input: Item number and amount of items to be sold
* The output: None
* The Function operation: If given item number does exist in catalog, exception is thrown
* 					      and item is not sold.
* 					      If item's amount in stock is lower than wanted amount in
* 					      more than 10, exception is thrown and item is not sold.
* 					      If item's amount in stock is lower than wanted amount in 10 or
* 					      less, item is sold and a new order is made so after order item's
* 					      amount in stock will be 20.
* 					      If item is sold, sale is documented
***************************************************************************************/
void Inventory::sellItem(const short itemNum, const int amount) throw (NoItemError, TooManyOrderedError, bad_alloc) {

	// check if an item with given number exists
	if (m_catalog.end() == m_catalog.find(itemNum)) {
		// item does not exist, throw exception
		throw NoItemError(itemNum);
	}

	// check if can order given amount
	if (m_stock[itemNum] + MAX_AMOUNT_DIFF < amount) {
		// stock amount is lower in more than 10 from ordered amount, cannot order
		throw TooManyOrderedError(itemNum, amount);
	}

	// item can be sold
	Sale newSale = Sale(amount, m_catalog[itemNum].getPointer()); // create a new sale of the specific item

	int originalStockAmount = m_stock[itemNum]; // save stock amount before reducing it
	m_stock[itemNum] -= amount; // reduce stock

	// check if ordered amount (now valid) is bigger than stock amount before sale
	if (originalStockAmount < amount) {

		// order product so after order is received, amount in stock will be 20
		int newOrderID = m_orderTracker.size()+1;
		MyAuto_ptr<Order> newOrder = new Order(/*m_catalog*/newOrderID, itemNum, -m_stock[itemNum]+BALANCE_AMOUNT);
		m_orderTracker[/*m_catalog*/newOrderID] = newOrder; // add new order to order tracker
		// update sale with new order
		newSale.updateOrder( (*m_orderTracker[newOrderID]) );
	}

	m_salesDoc.insert(newSale); // document new sale
}

/***************************************************************************************
* function name: void printSaleDoc() const
* The Input: None
* The output: None
* The Function operation: Prints array that contains each sale-document-string.
* 						  Each document-string is inserted to array's end, therefore
* 						  printing the array from its start will print the strings from
* 						  the earliest to the last
***************************************************************************************/
void Inventory::printSaleDoc() const {
	cout << m_salesDoc; // print array
}
